#include "GLImage.hpp"
#include <spdlog/spdlog.h>
#include <stdexcept>

static long objectCounter=0;

GLImage::GLImage()
{
  auto ElementNameFactory=[](){
    return ((std::stringstream())<<"Element"<<objectCounter++).str();
  };
  loop=g_main_loop_new(nullptr,false);
  appsrc=gst_element_factory_make("appsrc",ElementNameFactory().c_str());
  videoconvert=gst_element_factory_make("videoconvert",ElementNameFactory().c_str());
  glsink=gst_element_factory_make("gtkglsink",ElementNameFactory().c_str());
  pipeline=gst_pipeline_new(ElementNameFactory().c_str());
  if(!appsrc || !videoconvert || !glsink || !pipeline)
    throw std::runtime_error("无法创建全部的Gstelement元素");
  GtkWidget* glWidget;
  //从gstreamer中获取gtk组件
  g_object_get(glsink,"widget",&glWidget,nullptr);
  //将组件包装为C++对象
  gtkObject=Glib::wrap(glWidget,true);
  gst_bin_add_many(GST_BIN(pipeline),appsrc,videoconvert,glsink,nullptr);
  GstCaps* caps=gst_caps_new_simple("video/x-raw",
                                    "format",G_TYPE_STRING,"RGB",
                                    "width",G_TYPE_INT,1920,
                                    "height",G_TYPE_INT,1080,
                                    "framerate",GST_TYPE_FRACTION,50,1,
                                    nullptr
                                    );
  if(!gst_element_link_filtered(appsrc,videoconvert,caps))
    throw std::runtime_error("Can't link appsrc to videoconvert use this caps");
  gst_caps_unref(caps);

  if(!gst_element_link(videoconvert,glsink))
    throw std::runtime_error("Can't link videoconvert to glsink use this caps");

  gst_element_set_state(pipeline,GST_STATE_PLAYING);
  workThread=std::thread([this](){
    g_main_loop_run(loop);
    gst_element_set_state(pipeline,GST_STATE_NULL);
    gst_object_unref(GST_OBJECT(pipeline));
    g_main_loop_unref(loop);
    loop=nullptr;
  });
}

GLImage::~GLImage()
{
  gst_app_src_end_of_stream((GstAppSrc*)appsrc);
  workThread.join();
}

Gtk::Widget* GLImage::GetGtkObject()
{
  return gtkObject;
}

void GLImage::ShowImage(const ImageType& data)
{
  //申请一个新的缓存
  GstBuffer* buffer=gst_buffer_new();
  //分配内存
  GstMemory* memory=gst_allocator_alloc(nullptr,data.data_size,nullptr);
  //获得数据写入的位置
  GstMapInfo info;
  if(!gst_memory_map(memory,&info,GST_MAP_WRITE))
    throw std::runtime_error("Can't get Gstreamer memory");
  memcpy(info.data,data.data,data.data_size);
  gst_memory_unmap(memory,&info);
  //将memory添加到buffer中
  gst_buffer_append_memory(buffer,memory);
  //发送buffer
  if(gst_app_src_push_buffer((GstAppSrc*)appsrc,buffer)!=GST_FLOW_OK)
    spdlog::info("发送图像到压缩管线失败");
}


